package com.weixin.xplore.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.id.NanoId;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.weixin.xplore.config.StpClientUtil;
import com.weixin.xplore.controller.domain.request.*;
import com.weixin.xplore.controller.domain.response.SysUserGetLoginUserVO;
import com.weixin.xplore.dao.entity.SysUser;
import com.weixin.xplore.dao.service.PointOperatorService;
import com.weixin.xplore.dao.service.SysUserDaoService;
import com.weixin.xplore.domain.AuthAccountSendCheckCode;
import com.weixin.xplore.exception.CommonException;
import com.weixin.xplore.helper.WechatHelper;
import com.weixin.xplore.service.SysSettingBizService;
import com.weixin.xplore.service.SysUserBizService;
import com.weixin.xplore.utils.JsonUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@RequiredArgsConstructor
public class SysUserBizServiceImpl implements SysUserBizService {
    private final SysUserDaoService sysUserDaoService;
    private Map<String, AuthAccountSendCheckCode> checkCodeMap = new HashMap<>();

    private final WechatHelper wechatHelper;
    private final PointOperatorService pointOperatorService;
    private final SysSettingBizService settingBizService;


    @Override
    public synchronized Boolean sendCheckCode(AuthAccountSendCheckCodeRequest authAccountPasswordLoginParam) {

        String phone = authAccountPasswordLoginParam.getPhone();
        AuthAccountSendCheckCode authAccountSendCheckCode = checkCodeMap.get(phone);
        if (ObjectUtil.isNotNull(authAccountSendCheckCode)) {
            Date lastValidTime = authAccountSendCheckCode.getLastValidTime();
            if (DateUtil.betweenMs(lastValidTime, DateUtil.date()) <= 60) {
                Assert.isTrue(true, "发送时间间隔小于60ms");
            }
        } else {
            authAccountSendCheckCode = new AuthAccountSendCheckCode();
        }
        authAccountSendCheckCode.setLastValidTime(DateUtil.date());
        // 生成手机验证码的值，随机6为数字
        String phoneValidCode = RandomUtil.randomNumbers(6);
        authAccountSendCheckCode.setCheckCode(phoneValidCode);
        authAccountSendCheckCode.setSendCount(authAccountSendCheckCode.getSendCount() + 1);
        checkCodeMap.put(phone, authAccountSendCheckCode);
        return Boolean.TRUE;
    }

    @Override
    public String register(AuthAccountRegisterRequest authAccountPasswordLoginParam) {
        String phone = authAccountPasswordLoginParam.getPhone();
        Boolean b = settingBizService.queryValueByKey("login.checkCodeValid", Boolean.class, true);
        if (BooleanUtil.isTrue(b)) {
            AuthAccountSendCheckCode authAccountSendCheckCode = checkCodeMap.get(phone);
            Assert.isTrue(ObjectUtil.isNull(authAccountSendCheckCode), "获取短信发送记录失败");
            Assert.isTrue(StrUtil.equals(authAccountSendCheckCode.getCheckCode(), authAccountPasswordLoginParam.getCheckCode()), "验证码错误");
        }
        SysUser sysUser = sysUserDaoService.queryByAccount(authAccountPasswordLoginParam.getPhone());
        Assert.isTrue(ObjectUtil.isNull(sysUser), "用户已经存在");
        sysUser = new SysUser();
        sysUser.setAccount(authAccountPasswordLoginParam.getPhone());
        sysUser.setName(authAccountPasswordLoginParam.getName());
        sysUser.setPhone(authAccountPasswordLoginParam.getPhone());
        //获取openId
        String openId = wechatHelper.getOpenId(authAccountPasswordLoginParam.getCode());
        Map<String, Object> result = Maps.newHashMap();
        result.put("openId", openId);
        result.put("code", authAccountPasswordLoginParam.getCode());
        //绑定手机号也应该增加积分
        result.put("currentPoints", 0L);
        //注册时间
        result.put("registerTime", DateUtil.date());
        //邀请码
        result.put("invitationCode", NanoId.randomNanoId());

        result.put("deliverAddress", authAccountPasswordLoginParam.getDeliverAddress());
        result.put("device", authAccountPasswordLoginParam.getDevice());
        result.put("freezePoints", 0L);
        sysUser.setExtend(JsonUtil.toStr(result));
        sysUserDaoService.save(sysUser);

        String invitationCode = authAccountPasswordLoginParam.getInvitationCode();
        if (StrUtil.isNotBlank(invitationCode)) {

            pointOperatorService.invitation(invitationCode, sysUser.getId());
        }
        //自动登录
        return "";
    }

    @Override
    public Boolean signIn() {
        //普通每日签到	15 积分（连续 7 天额外奖励 30 积分）
        //会员20 积分（连续 7 天额外奖励 40 积分）
        //连续签到7天才有额外奖励
        Object loginId = StpClientUtil.getLoginId();
        if (ObjectUtil.isNull(loginId)) {
            return null;
        }

        return pointOperatorService.sign(loginId.toString());
    }

    @Override
    public String login(AuthAccountAutoLoginRequest authAccountPasswordLoginParam) {
        String phone = authAccountPasswordLoginParam.getPhone();
        Boolean b = settingBizService.queryValueByKey("login.checkCodeValid", Boolean.class, true);
        if (BooleanUtil.isTrue(b)) {
            AuthAccountSendCheckCode authAccountSendCheckCode = checkCodeMap.get(phone);
            Assert.isTrue(ObjectUtil.isNull(authAccountSendCheckCode), "获取短信发送记录失败");
            Assert.isTrue(StrUtil.equals(authAccountSendCheckCode.getCheckCode(), authAccountPasswordLoginParam.getCheckCode()), "验证码错误");
        }
        SysUser sysUser = sysUserDaoService.queryByAccount(authAccountPasswordLoginParam.getPhone());
        Assert.isTrue(ObjectUtil.isNotNull(sysUser), "用户获取失败已经存在");
// 执行登录
        StpClientUtil.login(sysUser.getId(), authAccountPasswordLoginParam.getDevice());
        // 缓存用户信息，此处使用TokenSession为了指定时间内无操作则自动下线
        StpClientUtil.getTokenSession().set("loginUser", sysUser);
        // 返回token
        return StpClientUtil.getTokenInfo().tokenValue;
    }

    @Override
    public List<SysUser> pageList(SysUserPageQueryRequest queryRequest) {
        return sysUserDaoService.pageList(queryRequest);
    }

    @Override
    public Boolean update(SysUser sysUser) {
        return sysUserDaoService.updatePopint(sysUser.getId(), sysUser.getExtend());
    }

    @Override
    public SysUserGetLoginUserVO getLoginUser() {
        Object loginId = StpClientUtil.getLoginId();
        SysUserGetLoginUserVO sysUserGetLoginUserVO = null;
        if (ObjectUtil.isNotNull(loginId)) {
            SysUser sysUser = sysUserDaoService.queryById(loginId.toString());
            if (ObjectUtil.isNotNull(sysUser)) {
                sysUserGetLoginUserVO = new SysUserGetLoginUserVO();
                sysUserGetLoginUserVO.setId(sysUser.getId());
                sysUserGetLoginUserVO.setName(sysUser.getName());
                sysUserGetLoginUserVO.setPhone(sysUser.getPhone());
                Long currentPoints = sysUser.getCurrentPoints();
                sysUserGetLoginUserVO.setCurrentPoints(currentPoints);
                sysUserGetLoginUserVO.setIsVip(sysUser.getIsVip());
                sysUserGetLoginUserVO.setAvatar(sysUser.getAvatar());
                sysUserGetLoginUserVO.setInvitationCode(sysUser.getInvitationCode());
            }
        }
        return sysUserGetLoginUserVO;
    }

    @Override
    public Boolean updateBasicInfo(SysUserUpdateBasicInfoRequest sysUser) {
        SysUser user = sysUserDaoService.queryById(sysUser.getId());
        if (ObjectUtil.isNull(user)) {
            return Boolean.FALSE;
        }
        user.setAge(sysUser.getAge());
        user.setGender(sysUser.getGender());
        user.setMailingAddress(sysUser.getAddress());
        user.setName(sysUser.getName());
        //完善信息可获取少量积分；
        return sysUserDaoService.updateById(user);
    }

    private String execLoginC(SysUser sysUser) {
        // 校验状态
        if (!StrUtil.equalsAnyIgnoreCase(sysUser.getUserStatus(), "enabled")) {
            throw new CommonException("用户已经停用");
        }
        // 执行登录
        StpClientUtil.login(sysUser.getId(), "miniapp");
        // 缓存用户信息，此处使用TokenSession为了指定时间内无操作则自动下线
        StpClientUtil.getTokenSession().set("loginUser", sysUser);
        // 返回token
        return StpClientUtil.getTokenInfo().tokenValue;
    }

}
